<?php
/**
* 支付模块 工具类
*
* 支付模块 工具类的注意及说明
* 以下use模块请不要互相伤害
*
* @author    xiecz <xiecz@yunys.com.cn>
* @copyright 2016 QuanZhouYunYiShang Inc.
*/
namespace App\Services\Tool\Pay;

use Illuminate\Support\Facades\DB;
use Request, Log, Session;
use App\Services\Tool\GeneralTool;
use App\Services\Tool\Pay\AlipayTool;

class PayTool{
	function __construct(AlipayTool $alipayTool){
		$this->alipayTool = $alipayTool;
	}
	//public static $key			= 'bgwem6s53tpw82qlir48i8bekutzn7sx';
	/**
		支付宝
		参数：
			out_trade_no			订单编号
			body					内容
			total_fee				金额
			subject					商品标题
	 */
	function alipay($input){
		//$input['total_fee'] = '0.01';
		$re				= DB::table('alipay')->first();
		$time 			= time();

		$arr['app_id']      = $re->app_id;
		$arr['method']      = 'alipay.trade.app.pay';
		$arr['format']      = 'JSON';
		// $arr['charset']     = 'utf-8'
		$arr['sign_type']   = 'RSA';
		$arr['timestamp']   = date('Y-m-d H:i:s',$time);
		$arr['version']     = '1.0';
		$arr['notify_url']  = env('HOME_URL') . 'api/pay/alipay-notify';
		// $arr['biz_content'] = '{'.
		// 						 '"body":"'.$input['body'].'",'.
		// 						 '"subject":"'.$input['subject'].'",'.
		// 						 '"out_trade_no":"'.$input['out_trade_no'].'",'.
		// 						 '"total_amount":"'.$input['total_fee'].'",'.
		// 						 '"seller_id":"'.$re->seller_id.'",'.
		// 						 '"product_code":"QUICK_MSECURITY_PAY",'.
		// 						 '"goods_type":"1"'.
		// 					  '}';
		$arr['biz_content'] = [
								'body'         => $input['body'],
								'subject'      => $input['subject'],
								'out_trade_no' => $input['out_trade_no'],
								'total_amount' => $input['total_fee'],
								'seller_id'    => $re->seller_id,
								'product_code' => 'QUICK_MSECURITY_PAY',
								'goods_type'   => 1
							   ];
		$arr['biz_content'] = urldecode(json_encode($arr['biz_content']));
		$data               = $this->alipayTool->getSignContent($arr);

		$arr['sign']        = $this->alipayTool->rsaSign($data,env('alipay_private_key'));

		foreach($arr as $k=>$v){
			$arr[$k] = urlencode($v);
		}

		$str  = $this->alipayTool->getSignContent($arr);
		return ['order_info' => $str];
	}

	/**
		支付宝有密退款
		参数：
			trade_no				交易号
			refund_amount			金额
			notify_url				回调地址
	 */
	function alipay_refund($input){


		$re				= DB::table('alipay')->first();
		$re->key		= 'bgwem6s53tpw82qlir48i8bekutzn7sx';

		$re->timestamp  = date('Y-m-d H:i:s',time());
		$url			= 'https://mapi.alipay.com/gateway.do';

		//$re->app_id     = '2016022601164789';

		$str			= 'batch_no='.$input['trade_no'].
						  '&batch_num=1'.
						  '&detail_data='.$input['trade_no'].'^'.$input['refund_amount'].'^'.'正常退款'.
						  '&_input_charset='.$re->_input_charset.
						  '&notify_url='.$input['notify_url'].
						  '&partner='.$re->partner.
						  '&refund_date='.$re->timestamp.
						  '&seller_user_id='.$re->partner.
						  '&service=refund_fastpay_by_platform_pwd'.
						  $re->key;
		Log::info($str);
		//MD5

		$sign			= strtoupper(md5($str));
		//dd($sign);
		$request		= 'service=refund_fastpay_by_platform_pwd'.
						  '&partner='.$re->partner.
						  '&_input_charset='.$re->_input_charset.
						  '&notify_url='.$input['notify_url'].
						  '&seller_user_id='.$re->partner.
						  '&refund_date='.$re->timestamp.
						  '&batch_no='.$input['trade_no'].
						  '&batch_num=1'.
						  '&detail_data='.$input['trade_no'].'^'.$input['refund_amount'].'^'.'正常退款'.
						  '&sign='.$sign.
						  '&sign_type=MD5';
		$url			.= '?'.$request;
		return $url;
		Log::info($request);
		$header[]	= "Content-type: application/json";//定义content-type
		$ch			= curl_init ();
		curl_setopt($ch, CURLOPT_TIMEOUT,30);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_URL,$url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,false);
		curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
		curl_setopt($ch, CURLOPT_SSLCERT,storage_path().DIRECTORY_SEPARATOR.'alipay'.DIRECTORY_SEPARATOR.'cacert.pem');
		curl_setopt($ch, CURLOPT_HTTPHEADER,$header);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
		curl_setopt($ch, CURLOPT_POST, 1);
		$response	= curl_exec($ch);
		var_dump(curl_error($ch));
		curl_close($ch);
		Log::info($response);
		dd($response);
	}

	/**
		微信
		参数：
			trade_type				支付类型
			out_trade_no			订单编号
			total_fee				金额
			body					商品名称
			attach					优惠券
			platform				平台
			JSAPI时openid
	 */
	function wxpay($input){
		//获取微信支付账户参数
		$re						= $this->getWeixinInfo($input);

		//添加订单编号随机串
		$substr					= '_'.substr(time().'',-4);


		//修改订单随机串
		DB::table('orders')->where('order_id',$input['order_id'])->update(array('substr'=>$substr));

		$input['out_trade_no']	.= $substr;

		$input['trade_type']	= isset($input['trade_type'])?$input['trade_type']:'APP';
		$input['total_fee']		= intval($input['total_fee']*100);

		//$input['total_fee']     = 1;

		//支付类型为JSAPI时
		if($input['trade_type']=='JSAPI'){
			$re->openid			= isset($input['openid']) ? $input['openid'] : '';
		}
		//随机数
		$nonce_str				= md5(time().mt_rand(0,1000));
		//签名准备
		$signs					= 'appid='.$re->appid.
								  '&attach='.$input['attach'].
								  '&body='.$input['body'].
								  '&mch_id='.$re->mch_id.
								  '&nonce_str='.$nonce_str.
								  '&notify_url=' . env('HOME_URL') . $re->notify_url;
		//支付类型为JSAPI时
		if($input['trade_type']=='JSAPI'){
			$signs				.= '&openid='.(isset($input['openid'])?$input['openid']:'');
		}
		$signs					.=	'&out_trade_no='.$input['out_trade_no'].
									'&product_id='.$input['out_trade_no'].
									'&spbill_create_ip='.$re->spbill_create_ip.
									'&total_fee='.$input['total_fee'].
									'&trade_type='.$input['trade_type'];
		$signs					.= '&key='.$re->key;
		try{
			Log::info($signs);
		}catch(\Exception $e){

		}

		//签名
		$sign					= strtoupper(md5($signs));


		//xml
		$str					=	'<xml>'.
									'<appid>'.$re->appid.'</appid>'.
									'<attach>'.$input['attach'].'</attach>'.
									'<body>'.$input['body'].'</body>'.
									'<mch_id>'.$re->mch_id.'</mch_id>'.
									'<nonce_str>'.$nonce_str.'</nonce_str>'.
									'<notify_url>' . env('HOME_URL') . $re->notify_url .'</notify_url>';

		if($input['trade_type']=='JSAPI'){
			$str				.= '<openid>'.$re->openid.'</openid>';
		}

		$str					.=	'<out_trade_no>'.$input['out_trade_no'].'</out_trade_no>'.
									'<product_id>'.$input['out_trade_no'].'</product_id>'.
									'<sign>'.$sign.'</sign>'.
									'<spbill_create_ip>'.$re->spbill_create_ip.'</spbill_create_ip>'.
									'<total_fee>'.$input['total_fee'].'</total_fee>'.
									'<trade_type>'.$input['trade_type'].'</trade_type>'.
									'</xml>';

		//统一下单请求
		$url					= 'https://api.mch.weixin.qq.com/pay/unifiedorder'; //接收xml数据的文件
		$header[]				= "Content-type: text/xml";//定义content-type为xml,注意是数组
		$ch = curl_init ($url);
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
		curl_setopt($ch, CURLOPT_HTTPHEADER,$header);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_POST, 1);
		curl_setopt($ch,CURLOPT_POSTFIELDS, $str);
		$response				= curl_exec($ch);

		$result					= (array)simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA);
		curl_close($ch);
		try{
			Log::info($result);
		}catch(\Exception $e){

		}

		//dd($result);
		if($result['return_code']=='SUCCESS'&&$result['result_code']=='SUCCESS'){
			$result['code_url']	= isset($result['code_url'])?$result['code_url']:'';
			$time				= time();
			$deeplink			= '';
			if($input['trade_type']=='WAP'){
				$str			= 'appid='.$result['appid'].
								  '&noncestr='.$result['nonce_str'].
								  '&package='.'WAP'.
								  '&prepayid='.$result['prepay_id'].
								  '&timestamp='.$time.
								  '&key='.$re->key;
				Log::info($str);
				$signx			= strtoupper(md5($st));
				$deeplink		= 'appid='.urlencode($result['appid']).
								  '&noncestr='.urlencode($result['nonce_str']).
								  '&package='.urlencode('WAP').
								  '&prepayid='.urlencode($result['prepay_id']).
								  '&timestamp='.urlencode($time).
								  '&sign='.urlencode($signx);
				$deeplink		= 'weixin://wap/pay?'.urlencode($deeplink);
			}
			if($input['trade_type']=='JSAPI'){
				$str			= 'appid='.$result['appid'].
								  '&noncestr='.$result['nonce_str'].
								  '&package=prepay_id='.$result['prepay_id'].
								  '&signtype=MD5'.
								  '&timestamp='.$time.
								  '&key='.$re->key;
				$signx			= strtoupper(md5($str));
			}
			$str				= 'appid='.$re->appid.
								  '&noncestr='.$nonce_str.
								  '&package='.$re->package.
								  '&partnerid='.$result['mch_id'].
								  '&prepayid='.$result['prepay_id'].
								  '&timestamp='.$time.
								  '&key='.$re->key;
			$signx				= strtoupper(md5($str));
			$arr				= GeneralTool::createResult(array('code_url'=>$result['code_url'],
																  'prepay_id'=>$result['prepay_id'],
														          'sign'=>$signx,
																  'nonceStr'=>$nonce_str,
																  'timeStamp'=>$time,
																  'partnerId'=>$result['mch_id'],
																  'appid'=>$re->appid,
																  'package'=>$re->package,
																  'order_id'=>$input['out_trade_no'],
																  'total_fee'=>$input['total_fee'].'',
																  'deeplink'=>$deeplink,
																  'trade_type'=>$input['trade_type']),
															'M00000');

			return $arr;
		}
		return GeneralTool::createResult('','M00001');
	}

	/**
		获取微信账户信息
		参数：
			trade_type				支付类型
			platform				平台
	 */
	static function getWeixinInfo($input){

		if(!isset($input['trade_type'])&&!isset($input['platform'])){
				$wx = DB::table('weixin')->where(['type'=>'APP'])->first();
				return $wx;
		}

		switch($input['trade_type']){
			case 'APP':
				$wx = DB::table('weixin')->where(['type'=>(isset($input['platform'])&&$input['platform']=='IPad'?'APPIPad':'APP')])->first();
				return $wx;
			case 'JSAPI':
				$wx = DB::table('weixin')->where(['type'=>'JSAPI'])->first();
				return $wx;
			default:
				$wx = DB::table('weixin')->where(['type'=>(isset($input['platform'])&&$input['platform']=='IPad'?'APPIPad':'APP')])->first();
				return $wx;
		}
	}

	/**
		微信退款
		参数：
			out_refund_no			商户退款单号
			refund_fee				退款金额
			total_fee				总金额
			transaction_id			交易号
			trade_type			    支付平台 APP JSAPI
	 */
	static function wx_refund($input){
		//$input['total_fee']		= 1;
		//$input['refund_fee']	= 1;
		//获取微信支付账户参数
		$input['total_fee']		= intval($input['total_fee']*100);
		$input['refund_fee']	= intval($input['refund_fee']*100);
		$re						= self::getWeixinInfo($input);
		$re->cert				= storage_path().'/wx/apiclient_cert.pem';
		$re->cert_key			= storage_path().'/wx/apiclient_key.pem';
		if($input['trade_type']== 'JSAPI'){
			$re->cert			= storage_path().'/wx/web/apiclient_cert.pem';
			$re->cert_key		= storage_path().'/wx/web/apiclient_key.pem';
		}
		//dd($re);
		$nonce_str				= md5(time().mt_rand(0,1000));

		$str					= 'appid='.$re->appid.
								  '&mch_id='.$re->mch_id.
								  '&nonce_str='.$nonce_str.
								  '&op_user_id='.$re->mch_id.
								  '&out_refund_no='.$input['out_refund_no'].
								  '&refund_fee='.$input['refund_fee'].
								  '&total_fee='.$input['total_fee'].
								  '&transaction_id='.$input['transaction_id'].
								  '&key='.$re->key;
		$sign					= strtoupper(md5($str));

		//xml
		$xml					= '<xml>'.
								  '<appid>'.$re->appid.'</appid>'.
								  '<mch_id>'.$re->mch_id.'</mch_id>'.
								  '<nonce_str>'.$nonce_str.'</nonce_str>'.
								  '<op_user_id>'.$re->mch_id.'</op_user_id>'.
								  '<out_refund_no>'.$input['out_refund_no'].'</out_refund_no>'.
								  '<refund_fee>'.$input['refund_fee'].'</refund_fee>'.
								  '<total_fee>'.$input['total_fee'].'</total_fee>'.
								  '<transaction_id>'.$input['transaction_id'].'</transaction_id>'.
								  '<sign>'.$sign.'</sign>'.
								  '</xml>';

		//申请退款请求
		$url					= 'https://api.mch.weixin.qq.com/secapi/pay/refund'; //接收xml数据的文件
		$header[]				= "Content-type: text/xml";//定义content-type为xml,注意是数组
		$ch = curl_init ($url);
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
		curl_setopt($ch, CURLOPT_HTTPHEADER,$header);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,false);
        curl_setopt($ch, CURLOPT_SSLCERTTYPE,'PEM');
        curl_setopt($ch, CURLOPT_SSLCERT,$re->cert);
        curl_setopt($ch, CURLOPT_SSLCERTPASSWD,$re->mch_id);
        curl_setopt($ch, CURLOPT_SSLKEYTYPE,'PEM');
        curl_setopt($ch, CURLOPT_SSLKEY,$re->cert_key);
		curl_setopt($ch, CURLOPT_POST, 1);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
		$response				= curl_exec($ch);
		Log::info($response);
		$result					= (array)simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA);

		curl_close($ch);
		Log::info($result);

		return $result;
	}


	/**
		银联
	 */
	public function UnionpayPhone($input){
		$union		= DB::table('unionpays')->first();
		//dd($union);
		//$certId	= $this->getCertIdByCerPath(storage_path().DIRECTORY_SEPARATOR.'unionpay'.DIRECTORY_SEPARATOR.'acp_test_enc.cer');
		$certId		= $this->getSignCertId(storage_path().DIRECTORY_SEPARATOR.'unionpay'.DIRECTORY_SEPARATOR.'acp_test_sign.pfx','000000');
		//dd($certId);
		//$input['total_fee'] = 0.01;
		$input['total_fee']	= intval($input['total_fee']*100);
		$txnType	= '01';
		$merId		= '777290058131040';
		$backUrl	= asset('api/order/test');
		$txnTime	= date('YmdHis',time());
		//dd($certId);
		//版本号
		$arr['version']		= $union->version;
		//编码方式
		$arr['encoding']	= $union->encoding;
		//证书ID
		$arr['certId']		= $certId;
		//签名方法
		$arr['signMethod']	= $union->signMethod;
		//交易类型
		$arr['txnType']		= $txnType;
		//交易子类
		$arr['txnSubType']	= $txnType;
		//产品类型
		$arr['bizType']		= '000201';
		if(isset($input['type'])&&$input['type']=='ApplePay'){
			$arr['bizType']	= '000802';
		}
		//渠道类型
		$arr['channelType']	= $union->channelType;
		//接入类型
		$arr['accessType']	= $union->accessType;
		//商户代码
		$arr['merId']		= $union->merId;
		//后台通知地址
		$arr['backUrl']		= isset($input['backUrl'])?$input['backUrl']:asset($union->backUrl);
		//商户订单号
		$arr['orderId']		= $input['order_id'];
		//交易币种
		$arr['currencyCode']= '156';
		//交易金额
		$arr['txnAmt']		= $input['total_fee'];
		//订单发送时间
		$arr['txnTime']		= $txnTime;
		//支付超时时间
		$arr['payTimeout']	= date('YmdHis',time()+60*60*24);
		//订单描述
		$arr['orderDesc']	= $input['body'];
		//dd($arr);
		$arr	= $this->sign($arr);
		$url	= 'https://gateway.95516.com/gateway/api/appTransReq.do';
		$result	= $this->post($arr,$url);
		//dd($result);
		return $result;
		$str   .= '&signature='.$sign;

	}

	/**
		银联退款
		参数：
			order_id		订单编号
			total_fee		订单金额
			trade_no		交易流水号
	 */
	public function unionRefund($input){
		$union		= DB::table('unionpays')->first();

		//版本号
		$arr['version']		= $union->version;
		//编码方式
		$arr['encoding']	= $union->encoding;
		//证书ID
		$arr['certId']		= $this->getSignCertId(storage_path().DIRECTORY_SEPARATOR.'unionpay'.DIRECTORY_SEPARATOR.'acp_test_sign.pfx','000000');
		//签名方法
		$arr['signMethod']	= $union->signMethod;
		//交易类型
		$arr['txnType']		= '04';
		//交易子类
		$arr['txnSubType']	= '00';
		//产品类型
		$arr['bizType']		= '000201';
		//渠道类型
		$arr['channelType']	= $union->channelType;
		//接入类型
		$arr['accessType']	= $union->accessType;
		//商户代码
		$arr['merId']		= $union->merId;
		//后台通知地址
		$arr['backUrl']		= asset('api/bail/union-refund');
		//商户订单号
		$arr['orderId']		= $input['order_id'];
		//交易金额
		$arr['txnAmt']		= intval($input['total_fee']*100);
		//订单发送时间
		$arr['txnTime']		= date('YmdHis',time());
		//原交易查询流水号
		$arr['origQryId']	= $input['trade_no'];

		$arr	= $this->sign($arr);
		$url	= 'https://gateway.95516.com/gateway/api/backTransReq.do';
		$result	= $this->post($arr,$url);
		//dd($result);
		return $result;

	}

	/**
	  * 取证书ID(.pfx)
	  *
	  * @return unknown
	  */
	function getSignCertId($cert_path, $cert_pwd) {
		$pkcs12certdata = file_get_contents ( $cert_path );
		openssl_pkcs12_read ( $pkcs12certdata, $certs, $cert_pwd );
		$x509data = $certs ['cert'];
		openssl_x509_read ( $x509data );
		$certdata = openssl_x509_parse ( $x509data );
		$cert_id = $certdata ['serialNumber'];
		return $cert_id;
	}

	/**
		获取certId
	 */
	function getCertIdByCerPath($cert_path) {
		$x509data = file_get_contents ( $cert_path );
		openssl_x509_read ( $x509data );
		$certdata = openssl_x509_parse ( $x509data );
		$cert_id = $certdata ['serialNumber'];
		return $cert_id;
	}

	/**
	    讲数组转换为string
	    @param $para 数组
		@param $sort 是否需要排序
		@param $encode 是否需要URL编码
		@return string
	  */
	function createLinkString($para, $sort, $encode) {
		if($para == NULL || !is_array($para))
			return "";

		$linkString = "";
		if ($sort) {
			$para = $this->argSort ( $para );
		}
		while ( list ( $key, $value ) = each ( $para ) ) {
			if ($encode) {
				$value = urlencode ( $value );
			}
			$linkString .= $key . "=" . $value . "&";
		}
		// 去掉最后一个&字符
		$linkString = substr ( $linkString, 0, count ( $linkString ) - 2 );

		return $linkString;
	}

	/**
	  * 签名
      * @param req 请求要素
      * @param resp 应答要素
      * @return 是否成功
      */
	function sign($params, $cert_path='unionpay'.DIRECTORY_SEPARATOR.'acp_test_sign.pfx', $cert_pwd='000000') {
		$cert_path = storage_path().DIRECTORY_SEPARATOR.$cert_path;
		if(isset($params['signature'])){
			unset($params['signature']);
		}
		// 转换成key=val&串
		$params_str = $this->createLinkString ( $params, true, false );
		Log::Info( "签名key=val&...串 >" . $params_str );

		$params_sha1x16 = sha1 ( $params_str, FALSE );
		Log::Info( "摘要sha1x16 >" . $params_sha1x16 );

		$private_key = $this->getPrivateKey ( $cert_path, $cert_pwd );
		// 签名
		$sign_falg = openssl_sign ( $params_sha1x16, $signature, $private_key, OPENSSL_ALGO_SHA1 );
		if ($sign_falg) {
			$signature_base64 = base64_encode ( $signature );
			Log::Info( "签名串为 >" . $signature_base64 );
			$params ['signature'] = $signature_base64;
			return $params;
		} else {
			Log::Info( ">>>>>签名失败<<<<<<<" );
		}
	}

	/**
		返回(签名)证书私钥 -
		@return unknown
	 */
	function getPrivateKey($cert_path='unionpay'.DIRECTORY_SEPARATOR.'acp_test_sign.pfx', $cert_pwd='000000') {
		//$cert_path = storage_path().DIRECTORY_SEPARATOR.$cert_path;
		$pkcs12 = file_get_contents ( $cert_path );
		openssl_pkcs12_read ( $pkcs12, $certs, $cert_pwd );
		return $certs ['pkey'];
	}

	/**
		对数组排序
		@param $para 排序前的数组
		return 排序后的数组
	 */
	function argSort($para) {
		ksort ( $para );
		reset ( $para );
		return $para;
	}
	/**
		后台交易 HttpClient通信

		@param unknown_type $params
		@param unknown_type $url
		@return mixed
	 */
	function post($params, $url) {

		$opts = $this->createLinkString ( $params, false, true );
		//dd($opts);
		Log::Info ( "后台请求地址为>" . $url );
		Log::Info ( "后台请求报文为>" . $opts );

		$ch = curl_init ();
		curl_setopt ( $ch, CURLOPT_URL, $url );
		curl_setopt ( $ch, CURLOPT_POST, 1 );
		curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, false ); // 不验证证书
		curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, false ); // 不验证HOST
		curl_setopt ( $ch, CURLOPT_SSLVERSION, 1 ); // http://php.net/manual/en/function.curl-setopt.php页面搜CURL_SSLVERSION_TLSv1
		curl_setopt ( $ch, CURLOPT_HTTPHEADER, array (
			'Content-type:application/x-www-form-urlencoded;charset=UTF-8'
		) );
		curl_setopt ( $ch, CURLOPT_POSTFIELDS, $opts );
		curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
		$html = curl_exec ( $ch );
		//dd($html);
		Log::Info ( "后台返回结果为>" . $html );

		if(curl_errno($ch)){
			$errmsg = curl_error($ch);
			curl_close ( $ch );
			Log::Info ( "请求失败，报错信息>" . $errmsg );
			return null;
		}
		if( curl_getinfo($ch, CURLINFO_HTTP_CODE) != "200"){
			$errmsg = "http状态=" . curl_getinfo($ch, CURLINFO_HTTP_CODE);
			curl_close ( $ch );
			Log::Info ( "请求失败，报错信息>" . $errmsg );
			return null;
		}
		curl_close ( $ch );
		$result_arr = $this->convertStringToArray ( $html );
		return $result_arr;
	}
	/**
		字符串转换为 数组

		@param unknown_type $str
		@return multitype:unknown
	 */
	function convertStringToArray($str) {
		return $this->parseQString($str);
	}

	/**
	 * key1=value1&key2=value2转array
	 * @param $str key1=value1&key2=value2的字符串
	 * @param $$needUrlDecode 是否需要解url编码，默认不需要
	 */
	function parseQString($str, $needUrlDecode=false){
		$result = array();
		$len = strlen($str);
		$temp = "";
		$curChar = "";
		$key = "";
		$isKey = true;
		$isOpen = false;
		$openName = "\0";

		for($i=0; $i<$len; $i++){
			$curChar = $str[$i];
			if($isOpen){
				if( $curChar == $openName){
					$isOpen = false;
				}
				$temp = $temp . $curChar;
			} elseif ($curChar == "{"){
				$isOpen = true;
				$openName = "}";
				$temp = $temp . $curChar;
			} elseif ($curChar == "["){
				$isOpen = true;
				$openName = "]";
				$temp = $temp . $curChar;
			} elseif ($isKey && $curChar == "="){
				$key = $temp;
				$temp = "";
				$isKey = false;
			} elseif ( $curChar == "&" && !$isOpen){
				$this->putKeyValueToDictionary($temp, $isKey, $key, $result, $needUrlDecode);
				$temp = "";
				$isKey = true;
			} else {
				$temp = $temp . $curChar;
			}
		}
		$this->putKeyValueToDictionary($temp, $isKey, $key, $result, $needUrlDecode);
		return $result;
	}


	function putKeyValueToDictionary($temp, $isKey, $key, &$result, $needUrlDecode) {
		if ($isKey) {
			$key = $temp;
			if (strlen ( $key ) == 0) {
				return false;
			}
			$result [$key] = "";
		} else {
			if (strlen ( $key ) == 0) {
				return false;
			}
			if ($needUrlDecode)
				$result [$key] = urldecode ( $temp );
			else
				$result [$key] = $temp;
		}
	}

	/**
	 * 验签

		@param String $params_str
		@param String $signature_str
	 */
	function verify($params) {
		//$certId	= $this->getSignCertId(storage_path().DIRECTORY_SEPARATOR.'unionpay'.DIRECTORY_SEPARATOR.'acp_test_sign.pfx','000000');
		//dd($params);
		// 公钥
		$public_key = $this->getPulbicKeyByCertId ( isset($params ['certId'])?$params ['certId']:$params ['cert_id']);
		//	echo $public_key.'<br/>';
		if(!isset($public_key)){
			return 0;
		}
		// 签名串
		$signature_str = $params ['signature'];
		unset ( $params ['signature'] );
		$params_str = $this->createLinkString ( $params, true, false );
		Log::info( '报文去[signature] key=val&串>' . $params_str );
		$signature = base64_decode ( $signature_str );

		//	echo date('Y-m-d',time());
		$params_sha1x16 = sha1 ( $params_str, FALSE );
		Log::info( '摘要shax16>' . $params_sha1x16 );

		//dd($public_key);
		$isSuccess = openssl_verify ( $params_sha1x16, $signature,$public_key, OPENSSL_ALGO_SHA1 );
		Log::info( $isSuccess ? 1 : 0 );
		return $isSuccess;
	}
	/**
	*	根据证书ID 加载 证书
	*
		@param unknown_type $certId
		@return string NULL
	 */
	function getPulbicKeyByCertId($certId) {

		Log::info( '报文返回的证书ID>' . $certId );
		// 证书目录
		$cert_dir = storage_path().DIRECTORY_SEPARATOR.'unionpay';
		//dd($cert_dir);
		Log::info( '验证签名证书目录 :>' . $cert_dir );
		$handle = opendir ( $cert_dir );
		if ($handle) {
			while ( $file = readdir ( $handle ) ) {
				clearstatcache ();
				$filePath = $cert_dir . DIRECTORY_SEPARATOR . $file;
				if (is_file ( $filePath )) {
					if (pathinfo ( $file, PATHINFO_EXTENSION ) == 'cer') {
						if ($this->getCertIdByCerPath ( $filePath ) == $certId) {
							closedir ( $handle );
							Log::info( '加载验签证书成功' );
							return $this->getPublicKey ( $filePath );
						}
					}
				}
			}
			Log::info( '没有找到证书ID为[' . $certId . ']的证书' );
		} else {
			Log::info( '证书目录 ' . $cert_dir . '不正确' );
		}
		closedir ( $handle );
		return null;
	}
	/**
		取证书公钥 -验签

		@return string
	 */
	function getPublicKey($cert_path) {
		return file_get_contents ( $cert_path );
	}
}
